#include <windows.h>
#include "windowsgui.h"
#include "resource.h"
#include "map.h"
#include "tinyxml/tinyxml.h"
#include "tinyxml/tinystr.h"
#include "util.h"
#include "editor.h"

InputDialog *InputDialog::thisptr = 0;
TriggerDialog *TriggerDialog::thisptr = 0;
ComboDialog *ComboDialog::thisptr = 0;
TriggerConfig TriggerDialog::conf;

const char *keyliststr[]={
"Up",
"Down",
"Left",
"Right",
"Enter",
"Cancel",
};

const char *minigamesstr[]={
    "Dance",
    "Lead Ball",
};

InputDialog::InputDialog()
{
    thisptr = this;
    input[0]=0;
    isok=false;
}

InputDialog::~InputDialog()
{
    thisptr = NULL;
}

bool InputDialog::DoModal( HWND parent )
{
    if( parent == 0 )
        parent = GetActiveWindow();
    DialogBoxA(0, MAKEINTRESOURCE(IDD_INPUTDIALOG), parent, DlgProc);
    return isok;
}

const char * InputDialog::GetInput()
{
    return input;
}

int WINAPI InputDialog::DlgProc( HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam )
{
    InputDialog *inputdlg = InputDialog::thisptr;
    switch(uMsg)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;
    case WM_COMMAND:
        if(IDINPUTOK == LOWORD(wParam))
        {
            HWND hedit = GetDlgItem(hwndDlg, IDC_EDITINPUT);
            GetWindowText(hedit, inputdlg->input, 1024);	
            if(inputdlg->input[0])
            {
                EndDialog(hwndDlg, 0);
                inputdlg->isok = true;
                return TRUE;
            }
        }
        else if(IDINPUTCANCEL == LOWORD(wParam))
        {
            EndDialog(hwndDlg, 0);
            inputdlg->isok = false;
            return TRUE;
        }
    }
    return FALSE;
}

TriggerDialog::TriggerDialog()
{
    thisptr = this;
    isok = false;
    triggerindex = -1;
    conditionindex = -1;
    actionindex = -1;
    for(int i=0;i<TRIG_NUM;i++)
    {
        trigger[i]=-1;
        condition[i]=-1;
        action[i]=-1;
    }
}

TriggerDialog::~TriggerDialog()
{

}

bool TriggerDialog::DoModal()
{
    DialogBoxA(0, MAKEINTRESOURCE(IDD_TRIGGERDLG), GetActiveWindow(), DlgProc);
    return isok;
}

int WINAPI TriggerDialog::DlgProc( HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam )
{
    TriggerDialog *dlg = TriggerDialog::thisptr;
    int ctrlid = LOWORD(wParam);
    switch(uMsg)
    {
    case WM_INITDIALOG:
        {
			Region *r = Editor::edtstate.curregion;
            SetWindowText( GetDlgItem(hwndDlg,IDC_REGIONNAME), Editor::edtstate.curregion->name.c_str() );
            if(r->trigger.triggertype >=0 && r->trigger.triggertype < dlg->conf.triggers.size())
            {
                TriggerDef &def = dlg->conf.triggers[r->trigger.triggertype];
                SetWindowText( GetDlgItem(hwndDlg,IDC_TRIGGER1), def.name.c_str() );
                dlg->trigger[0] = r->trigger.triggertype;
                if( r->trigger.data >=0 && def.paramdef.size() > 0)
                {
                    ParamDef &p = def.paramdef[0];
                    ComboListMode *l = dlg->CreateListMode( p.inputparam.c_str() );
                    dlg->trigger[1] = r->trigger.data;
                    for( int i=0;i<l->GetCount();i++ )
                    {
                        if( l->GetReturn(i) == r->action.data )
                            SetWindowText( GetDlgItem(hwndDlg,IDC_TRIGGER2), l->GetElemAt(i).c_str() );
                    }
                }
            }
            if(r->action.actiontype >=0 && r->action.actiontype < dlg->conf.actions.size())
            {
                ActionDef &def = dlg->conf.actions[r->action.actiontype];
                SetWindowText( GetDlgItem(hwndDlg,IDC_ACTION1), def.name.c_str() );
                dlg->action[0] = r->action.actiontype;
                if( r->action.data >=0 && def.paramdef.size() > 0)
                {
                    ParamDef &p = def.paramdef[0];
                    ComboListMode *l = dlg->CreateListMode( p.inputparam.c_str() );
                    dlg->action[1] = r->action.data;
                    for( int i=0;i<l->GetCount();i++ )
                    {
                        if( l->GetReturn(i) == r->action.data )
                            SetWindowText( GetDlgItem(hwndDlg,IDC_ACTION2), l->GetElemAt(i).c_str() );
                    }
                }
            }
        }
        return (INT_PTR)TRUE;
    case WM_COMMAND:
        if(IDOK == ctrlid)
        {	
            EndDialog(hwndDlg, 0);
            dlg->isok = true;
            char text[1024];
            GetWindowText( GetDlgItem(hwndDlg,IDC_REGIONNAME), text, 1024 );
            dlg->regionname = text;
            return TRUE;
        }
        else if(IDCANCEL == ctrlid)
        {
            EndDialog(hwndDlg, 0);
            dlg->isok = false;
            return TRUE;
        }
        else if(IDC_TRIGGER1 <= ctrlid && IDC_TRIGGER4 >= ctrlid)
        {
            if( IDC_TRIGGER1 == ctrlid )
            {
                ComboDialog cbdlg(new TriggerComboListMode());
                if( cbdlg.DoModal(hwndDlg) )
                {
                    dlg->trigger[0] = cbdlg.select;
                    dlg->triggerindex = 0;
                    ::SetWindowText(GetDlgItem(hwndDlg,IDC_TRIGGER1), cbdlg.selectstr.c_str());
                    for( int i=IDC_TRIGGER1+1;i<=IDC_TRIGGER4;i++ )
                    {
                        HWND btn = GetDlgItem(hwndDlg, i);
                        ::SetWindowText( btn, "" );
                    }
                    ParamDefVec &paramdef = dlg->conf.triggers[cbdlg.select].paramdef;
                    for( int i=0;i<paramdef.size();i++ )
                    {
                        HWND btn = GetDlgItem(hwndDlg,IDC_TRIGGER2+i);
                        if( btn != 0 )
                            ::SetWindowText( btn, paramdef[i].name.c_str() );
                    }
                }
            }
            else
            {
                if( dlg->trigger[0] == -1 )
                    break;
                ParamDefVec &paramdef = dlg->conf.triggers[dlg->trigger[0]].paramdef;
                if( ctrlid - IDC_TRIGGER2>=paramdef.size() )
                    break;
                ParamDef &param = paramdef[ctrlid - IDC_TRIGGER2];
                HWND btn = GetDlgItem(hwndDlg,ctrlid);
                if( param.inputtype == "List" )
                {
                    ComboDialog cbdlg(dlg->CreateListMode(param.inputparam.c_str()));
                    if( cbdlg.DoModal(hwndDlg) )
                    {
                        dlg->trigger[ctrlid-IDC_TRIGGER1] = cbdlg.value;
                        SetWindowText(btn, cbdlg.selectstr.c_str());
                    }
                }
            }
        }
        else if(IDC_ACTION1 <= ctrlid && IDC_ACTION4 >= ctrlid)
        {
            if( IDC_ACTION1 == ctrlid )
            {
                ComboDialog cbdlg(new ActionComboListMode());
                if( cbdlg.DoModal(hwndDlg) )
                {
                    dlg->action[0] = cbdlg.select;
                    ::SetWindowText(GetDlgItem(hwndDlg,IDC_ACTION1), cbdlg.selectstr.c_str());
                    for( int i=IDC_ACTION1+1;i<=IDC_ACTION4;i++ )
                    {
                        HWND btn = GetDlgItem(hwndDlg, i);
                        ::SetWindowText( btn, "" );
                    }
                    ParamDefVec &paramdef = dlg->conf.actions[cbdlg.select].paramdef;
                    for( int i=0;i<paramdef.size();i++ )
                    {
                        HWND btn = GetDlgItem(hwndDlg,IDC_ACTION2+i);
                        if( btn != 0 )
                            ::SetWindowText( btn, paramdef[i].name.c_str() );
                    }
                }
            }
            else
            {
                if( dlg->action[0] == -1 )
                    break;
                ParamDefVec &paramdef = dlg->conf.actions[dlg->action[0]].paramdef;
                if( ctrlid - IDC_ACTION2>=paramdef.size() )
                    break;
                ParamDef &param = paramdef[ctrlid - IDC_ACTION2];
                HWND btn = GetDlgItem(hwndDlg,ctrlid);
                if( param.inputtype == "List" )
                {
                    ComboDialog cbdlg(dlg->CreateListMode(param.inputparam.c_str()));
                    if( cbdlg.DoModal(hwndDlg) )
                    {
                        dlg->action[ctrlid-IDC_ACTION1] = cbdlg.value;
                        SetWindowText(btn, cbdlg.selectstr.c_str());
                    }
                }
            }
        }
    }
    return FALSE;
}

ComboListMode * TriggerDialog::CreateListMode( const char *name )
{
    ComboListMode *l = 0;
    if( strcmp(name,"KeyList")==0 )
        l = new KeyComboListMode;
    else if( strcmp(name,"RegionList")==0 )
        l = new RegionComboListMode;
    else if( strcmp(name,"MinigameList")==0 )
        l = new MinigameComboListMode;
    return l;
}

int KeyComboListMode::GetCount()
{
    return 6;
}

std::string KeyComboListMode::GetElemAt( int i )
{
    return keyliststr[i];
}

int MinigameComboListMode::GetCount()
{
    return 2;
}

std::string MinigameComboListMode::GetElemAt( int i )
{
    return minigamesstr[i];
}

int RegionComboListMode::GetCount()
{
    return MapManager::Instance().mRegions.size();
}

std::string RegionComboListMode::GetElemAt( int i )
{
    RegionMap::iterator iter = MapManager::Instance().mRegions.begin();
    while(i>0)
    {
        i--;
        iter++;
    }
    Region *r = iter->second;
    return r->name;
}

int RegionComboListMode::GetReturn( int i )
{
    RegionMap::iterator iter = MapManager::Instance().mRegions.begin();
    while(i>0)
    {
        i--;
        iter++;
    }
    Region *r = iter->second;
    return r->id;
}

ComboDialog::ComboDialog( ComboListMode *l )
{
    thisptr = this;
    select=-1;
    isok=false;
    listmode = l;
}

ComboDialog::~ComboDialog()
{
    delete listmode;
}

bool ComboDialog::DoModal( HWND parent )
{
    if( parent == 0 )
        parent = GetActiveWindow();
    DialogBoxA(0, MAKEINTRESOURCE(IDD_SELECTDLG), parent, DlgProc);
    return isok;
}

int WINAPI ComboDialog::DlgProc( HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam )
{
    ComboDialog *dlg = ComboDialog::thisptr;
    ComboListMode *listmode = dlg->listmode;
    HWND hcomb = GetDlgItem(hwndDlg, IDC_SELECTLIST);
    switch(uMsg)
    {
    case WM_INITDIALOG:
        {
            int count = listmode->GetCount();
            for( int i=0;i<count;i++ )
            {
                SendMessage(hcomb, CB_ADDSTRING, 0, (LPARAM)listmode->GetElemAt(i).c_str());
            }
        }
        return (INT_PTR)TRUE;
    case WM_COMMAND:
        if(IDOK == LOWORD(wParam))
        {	
            EndDialog(hwndDlg, 0);
            dlg->select = SendMessage(hcomb, CB_GETCURSEL, 0, 0);
            if( dlg->select != CB_ERR )
            {
                dlg->isok = true;
                dlg->value = dlg->listmode->GetReturn(dlg->select);
                dlg->selectstr = dlg->listmode->GetElemAt(dlg->select);
            }
            return TRUE;
        }
        else if(IDCANCEL == LOWORD(wParam))
        {
            EndDialog(hwndDlg, 0);
            dlg->isok = true;
            return TRUE;
        }
    }
    return FALSE;
}

void TriggerConfig::ReadConfig()
{
    const char *filename = "data\\Trigger.xml";
    TiXmlDocument doc;
    if( !doc.LoadFile(filename) )
        return;
    std::string name,inputtype,inputparam;
    TiXmlElement *node = doc.RootElement();
    TiXmlElement *triggernode = node->FirstChildElement("TriggerDef");
    while( triggernode != NULL )
    {
        TriggerDef def;
        def.name = GetXmlString(triggernode,"name");
        TiXmlElement *inputnode = triggernode->FirstChildElement("Input");
        while( inputnode!= NULL )
        {
            ParamDef p;
            p.name = GetXmlString(inputnode, "Name");
            p.inputtype = GetXmlString(inputnode, "Type");
            p.inputparam = GetXmlString(inputnode, p.inputtype.c_str());
            def.paramdef.push_back(p);
            inputnode = inputnode->NextSiblingElement();
        }
        triggers.push_back(def);
        triggernode = triggernode->NextSiblingElement();
    }
    
    node = node->NextSiblingElement("Action");
    TiXmlElement *actionnode = node->FirstChildElement("ActionDef");
    while( actionnode != NULL )
    {
        ActionDef def;
        def.name = GetXmlString(actionnode,"name");
        TiXmlElement *inputnode = actionnode->FirstChildElement("Input");
        while( inputnode!= NULL )
        {
            ParamDef p;
            p.name = GetXmlString(inputnode, "Name");
            p.inputtype = GetXmlString(inputnode, "Type");
            p.inputparam = GetXmlString(inputnode, p.inputtype.c_str());
            def.paramdef.push_back(p);
            inputnode = inputnode->NextSiblingElement();
        }
        actions.push_back(def);
        actionnode = actionnode->NextSiblingElement();
    }
}

int TriggerComboListMode::GetCount()
{
    return TriggerDialog::conf.triggers.size();
}

std::string TriggerComboListMode::GetElemAt( int i )
{
    return TriggerDialog::conf.triggers[i].name;
}

int ConditionComboListMode::GetCount()
{
    return TriggerDialog::conf.conditions.size();
}

std::string ConditionComboListMode::GetElemAt( int i )
{
    return TriggerDialog::conf.conditions[i].name;
}

int ActionComboListMode::GetCount()
{
    return TriggerDialog::conf.actions.size();
}

std::string ActionComboListMode::GetElemAt( int i )
{
    return TriggerDialog::conf.actions[i].name;
}
